#include <RSLib/Common.hpp>
#ifndef RSLIB___LOW_LEVEL_HPP
#define RSLIB___LOW_LEVEL_HPP
 
 
//---INCLUDE
//---------------------->
#include <RSLib/Types.hpp>
#include <memory.h>
 
 
 
namespace RSLib {
namespace LowLevel {
 
 
 
//---MACROS
//	Desc:	macros and a template function (mostly) to get pointers to methods
//	Note:	tested on VC6, VC7, VC8, GCC4
//----------------------------------------------------------------------------------->
template<typename T> Void* AddressToVoidPointer(T address){return *(Void**) &address;}
#define OBJECT_ADDRESS(class_,object_)	RSLib::LowLevel::AddressToVoidPointer(&object_)
#define METHOD_ADDRESS(class_,method_)	RSLib::LowLevel::AddressToVoidPointer(&class_::method_)
#define FUNCTION_ADDRESS(function_)		RSLib::LowLevel::AddressToVoidPointer(&function_)
 
 
 
}//namespace LowLevel
 
 
 
//---FUNCTIONS
//	Desc:	Pointers displacements
//-------------------------------------------------------------------------------------------------------------------------------------------->
template<typename T,typename U> inline T* DisplacedPointer(T* ptr, U bytes)					{return (T*) (reinterpret_cast<Byte*>(ptr) + bytes);}
template<typename T,typename U> inline const T* DisplacedPointer(const T* ptr, U bytes)	{return (T*) (reinterpret_cast<const Byte*>(ptr) + bytes);}
//template<typename T,typename U> inline Void DisplacePointer(T& ptr, U bytes)					{ptr = DisplacedPointer(ptr,bytes);}
template<typename T,typename U> inline Void DisplacePointer(T& ptr, U bytes)					{ptr = (T)(((Byte*)ptr) + bytes);}//using C casts for VC6 compat...
 
 
 
#if defined(ZeroMemory)
#define RSLIB___ZeroMemory_DEFINED
#pragma message("ZeroMemory is already defined as a macro and will hide RSLib::ZeroMemory. Use <RSLib/Windows.hpp> to have it automatically undefined while including windows headers.")
#pragma push_macro("ZeroMemory")
#undef ZeroMemory
#pragma push_macro("CopyMemory")
#undef CopyMemory
#endif
inline Void ZeroMemory(Pointer ptr, LargerUnsigned bytes)										{memset(ptr,0,bytes);}
template <typename T> void ZeroObjectMemory(T& object)											{ZeroMemory( &object , sizeof(T) );}
inline bool CompareMemory(const Void* a, const Void* b, LargerUnsigned bytes)				{return (memcmp(a,b,bytes) == 0);}
inline void CopyMemory(void* destination, const Void* source, LargerUnsigned bytes)		{memcpy(destination,source,bytes);}
 
inline void CopyStridedMemory(Void* destination, const Void* source, 
										LargerUnsigned itemBytes, LargerUnsigned itemCount = 1,
										LargerUnsigned destinationStride = 0, LargerUnsigned sourceStride = 0, 
										LargerUnsigned destinationOffset = 0, LargerUnsigned sourceOffset = 0)
{
	DisplacePointer(destination,destinationOffset);
	DisplacePointer(source,sourceOffset);
	
	for(LargerUnsigned i=0 ; i<itemCount ; i++)
	{
		CopyMemory(destination,source,itemBytes);
	//	use itemBytes for strides if zero is provided
		DisplacePointer(destination,destinationStride ? destinationStride : itemBytes);
		DisplacePointer(source,sourceStride ? sourceStride : itemBytes);
	}
}
#if defined(RSLIB___ZeroMemory_DEFINED)
#pragma pop_macro("ZeroMemory")
#pragma pop_macro("CopyMemory")
#endif
 
 
 
}//namespace RSLib
 
 
 
//---ASSEMBLY CODING
//----------------------------->
#define BEGIN_ASSEMBLY __asm {
#define ASSEMBLY __asm
#define END_ASSEMBLY }
 
 
 
//---RETURN ADRESS
//	Desc: VC intrinsics for dealing with return address
//---------------------------------------------------->
#if defined(RSLIB___VC_COMPILER)

extern "C" {
void * _AddressOfReturnAddress(void);
void * _ReturnAddress(void);
}
#pragma intrinsic(_AddressOfReturnAddress)
#pragma intrinsic(_ReturnAddress)

namespace RSLib {
namespace LowLevel {
 

//!NOTE: Unfortunately there exists no way to force compiler to inline :( 
//			which in this case would have been obviously the way to go...
//			So we have to use ugly macros instead of beautifully namespaced inline functions :(
//__forceinline void* ReturnAddress()				{return _ReturnAddress();}
//__forceinline void* AddressOfReturnAddress()	{return _AddressOfReturnAddress();}
#define RSLIB___ReturnAddress _ReturnAddress()
#define RSLIB___AddressOfReturnAddress _AddressOfReturnAddress()

 
}//namespace LowLevel
}//namespace RSLib

#endif//defined(RSLIB___VC_COMPILER)
 
 
 
#if defined(RSLIB___GCC_COMPILER)

namespace RSLib {
namespace LowLevel {
 
 
//inline void* ReturnAddress()				{return __builtin_return_address(0);}
////inline void* AddressOfReturnAddress()	{return &__builtin_return_address(0);}
#define RSLIB___ReturnAddress __builtin_return_address(0)
 
 
}//namespace LowLevel
}//namespace RSLib
 
#endif//defined(RSLIB___GCC_COMPILER)
 
 
 
#endif//RSLIB___LOWLEVEL_HPP